package benchmark.clients;

import benchmark.Client;
import benchmark.RequestCounter;

import generic.Request;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.concurrent.locks.ReentrantLock;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.sax.SAXSource;

import org.apache.log4j.Logger;
import org.ws4d.coap.Constants;
import org.ws4d.coap.connection.BasicCoapChannelManager;
import org.ws4d.coap.interfaces.CoapChannelManager;
import org.ws4d.coap.interfaces.CoapClient;
import org.ws4d.coap.interfaces.CoapClientChannel;
import org.ws4d.coap.interfaces.CoapRequest;
import org.ws4d.coap.interfaces.CoapResponse;
import org.ws4d.coap.messages.CoapEmptyMessage;
import org.ws4d.coap.messages.CoapRequestCode;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;

import domainspecific.types.Interval;
import domainspecific.types.MeterReadings;


public class MyCoapClient implements Client, CoapClient {
    private static String SERVER_ADDRESS = "localhost";
    private static int PORT = Constants.COAP_DEFAULT_PORT;
    static int counter = 0;
    CoapChannelManager channelManager = null;
    CoapClientChannel clientChannel = null;
    
    static private long numReadings = 0;
    static private String interval = "MINUTE";
    static
    {
    	if(System.getenv().containsKey("READINGS_NUMREADINGS")){
			numReadings = Long.parseLong(System.getenv().get("READINGS_NUMREADINGS"));
		}
    	if(System.getenv().containsKey("READINGS_INTERVAL")){
			interval = System.getenv().get("READINGS_INTERVAL");
		}
    }
    
    long begin = 0;
    private ReentrantLock lock;
    
    private static final Logger coapLogger = Logger.getLogger("coaplogger");
    
    public MyCoapClient()
    {
    	super();
    	if(System.getenv().containsKey("READINGS_HOST")){
			SERVER_ADDRESS = System.getenv().get("READINGS_HOST");
		}
		
		if(System.getenv().containsKey("READINGS_PORT")){
			PORT = Integer.parseInt(System.getenv().get("READINGS_PORT"));
		}
    	this.channelManager = BasicCoapChannelManager.getInstance();
    	try {
			clientChannel = channelManager.connect(this, InetAddress.getByName(SERVER_ADDRESS), PORT);
		} catch (UnknownHostException e) {
			System.err.println("Unknown host " + SERVER_ADDRESS + ": " + e.getMessage());
			System.exit(-1);
		}
		this.lock = new ReentrantLock();
    }
	@Override
	public void sendRequest() {
		// TODO Auto-generated method stub
		CoapRequest coapRequest = clientChannel.createRequest(true, CoapRequestCode.GET);
		StringBuilder sendPath = new StringBuilder("id=" + ((int) ( Math.random() * 100000))); // random meter id
		sendPath.append("&from=");
		// 1 day, 15 minute interval
		long tFrom=(int)(Math.random()*(java.lang.System.currentTimeMillis()/1000));
		sendPath.append(tFrom);
		sendPath.append("&numReadings=");
		sendPath.append(MyCoapClient.numReadings);
		sendPath.append("&interval=");
		sendPath.append(Interval.valueOf(interval));
		coapRequest.setUriQuery(sendPath.toString());
		begin = System.currentTimeMillis();
		clientChannel.sendMessage(coapRequest);
		synchronized(this.lock)
		{try {
			this.lock.wait(100);
		} catch (InterruptedException e) {
			System.out.println("Interrupted, continuing.");
		}}
	}

	@Override
    public void onConnectionFailed(CoapClientChannel channel, boolean notReachable, boolean resetByServer) {
        //System.out.println("Connection Failed");
    }

    @Override
    public void onResponse(CoapClientChannel channel, CoapResponse response) {
        ByteArrayInputStream bais = new ByteArrayInputStream(response.getPayload());
        
		try {
			JAXBContext jcontext = JAXBContext.newInstance(MeterReadings.class);
			MeterReadings readings = null;
			Unmarshaller unmarshal = jcontext.createUnmarshaller();

			readings = (MeterReadings) unmarshal.unmarshal(bais);
		} catch (JAXBException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		long finished = System.currentTimeMillis();
		long responseTime = (finished - begin);
		coapLogger.info("" + responseTime);
		synchronized(this.lock)
		{
			this.lock.notifyAll();
		}
		//System.out.println(readings.getReadings().size());
    }

    @Override
    public void onSeparateResponseAck(CoapClientChannel channel,
            CoapEmptyMessage message) {
        System.out.println("Received Ack of Separate Response");
    }

    @Override
    public void onSeparateResponse(CoapClientChannel channel,
            CoapResponse message) {
        System.out.println("Received Separate Response");
    }

}
